#include <iostream>
#include <event2/event.h>
#include <event2/listener.h>
#include <string.h>
#ifndef _WIN32
#include <signal.h>
#endif
using namespace std;
#define PORT 8080
//正常断开连接 超时不发送数据  都会进入
void client_cb(evutil_socket_t lfd, short which, void *arg){

        //1.水平触发 只要有数据没有处理 会一直进入 当然了第一次必须有数据 保证有一次触发
        //2 边缘触发 有数据时只进入一次
        //cout<<"."<<flush; return ; 

        event *ev = (event *)arg;

        //判断超时
        if(which & EV_TIMEOUT){
                cout<<"timeout"<<endl;
                //如果超时了 清理 event lfd
                event_free(ev);
                evutil_closesocket(lfd);
                return;
        }

        //char buf[1024] = {0};
        char buf[5]={0};//搞一个5 让发过来的数据大于5    边缘触发 没有读完全会造成缓冲区数据越来越多
        int len = recv(lfd, buf, sizeof(buf)-1, 0);
        if(len > 0){
                cout<<buf<<endl;
                //回复数据给客户端
                send(lfd, "ok", 2, 0);
        }else{
                //读不到 说明 客户端正常关闭了
                cout<<"client  normal close"<<flush;
                //读不到了需要清理 event lfd
                event_free(ev);
                evutil_closesocket(lfd);
        }
}
void listen_cb(evutil_socket_t sfd, short which, void *arg){
        cout<<"listen_cb"<<endl;
        //这个结构体用来保存客户端的
        sockaddr_in sin;
        socklen_t size = sizeof(sin);
        //读取连接信息
        evutil_socket_t client = accept(sfd, (sockaddr *)&sin, &size);
        char ip[16] = {0};
        evutil_inet_ntop(AF_INET, &sin.sin_addr, ip, sizeof(ip)-1);
        cout<<"client ip is "<<ip<<endl;
        
        //客户端数据读取事件
        event_base *base = (event_base*)arg;
        //水平触发
        event *ev = event_new(base, client, EV_READ|EV_PERSIST, client_cb, event_self_cbarg());
        //边缘触发
        //event *ev = event_new(base, client, EV_READ|EV_PERSIST|EV_ET, client_cb, event_self_cbarg());
        timeval t = {10, 0};
        event_add(ev, &t); //设置一个客户端多长时间没有发送数据
}
int main(int argc, char const *argv[]){
#ifdef _WIN32
        //初始化socket库
        WSADATA wsa;
        WSAStartup(MAKEWORD(2,2), &wsa);
#else
        //忽略管道信号 发送数据给已关闭的socket
        if(signal(SIGPIPE,SIG_IGN) == SIG_IGN){
                return 1;
        }
#endif
        //创建libevent的上下文
        event_base *base = event_base_new();

        cout<<"test event server !" <<endl;
        
        //使用原生的方法来创建socket   之前用的是libevent提供的evconnlistener_new_bind
        evutil_socket_t sock = socket(AF_INET, SOCK_STREAM,0);
        if(sock<=0){
                cerr<<"socket failed: "<<strerror(errno)<<endl;
                return -1;
        }

        //设置地址复用和非阻塞
        evutil_make_listen_socket_reuseable(sock);
        evutil_make_socket_nonblocking(sock);

        sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_port =htons(PORT);

        int ret = ::bind(sock, (sockaddr *)&sin, sizeof(sin)); //防止于std的冲突
        if(ret != 0){
                cerr<<"socket failed: "<<strerror(errno)<<endl;
                return -1;
        }

        listen(sock, 10);

        //默认水平触发
        event *ev = event_new(base, sock, EV_READ|EV_PERSIST,listen_cb,base);
        event_add(ev,NULL);

        event_base_dispatch(base);

        event_free(ev);
        evutil_closesocket(sock);
        event_base_free(base);
#ifdef _WIN32
        WSACleanup();
#endif
        return 0;
}